// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>

#include "getopt.h"
#include "mt19937ar.h"
#include "options.h"
#include "pmaths.h"
#include "utils.h"

#define DEFAULT_ROWS 1000
#define DEFAULT_COLS 1000
#define SUFFIX_TXT_FILE ".txt"
#define SUFFIX_DIMS_FILE ".dims.dat"
#define SUFFIX_MATRIX_TXT_FILE ".matrix.txt"
#define SUFFIX_MATRIX_BIN_FILE ".matrix.dat"
#define TYPE_DOUBLE "double"

struct option long_options[] = {
	{ "id", required_argument, NULL, 'i' }, // Run ID
	{ "dir", required_argument, NULL, 'd'}, // Local Output direct
	{ "type", required_argument, NULL, 't'}, // Data-type of the randomised data.
	{ "ncols", required_argument, NULL, 'c'}, 
	{ "nrows", required_argument, NULL, 'r'}, 
	{ "seed", required_argument, NULL, 's' }, // Seed value for the random number generator.
	{ 0,    0,    0,    0   } 
};

int write_dims(char *id, int nrows, int ncols, char *type, char *dir) {
	char output_file[FILE_PATH_LENGTH];
	BOOL jobDone = FALSE;
	FILE *out = NULL;

	sprintf(output_file, "%s%s%s", dir, id, SUFFIX_DIMS_FILE);
	out = fopen(output_file, "w");
	if (out != NULL) {
		if(fprintf(out, "%s %i %i\n", type, nrows, ncols)) jobDone = TRUE;
		fclose(out);
	}

	if (jobDone) return 1;
	else return 0;
}

int write_matrix_text(char *id, char *dir, MATRIX_T m, int nrows, int ncols) {
	char output_file[FILE_PATH_LENGTH];
	BOOL jobDone = FALSE;
	FILE *out = NULL;
	int i, j;

	sprintf(output_file, "%s%s%s", dir, id, SUFFIX_MATRIX_TXT_FILE);
	out = fopen(output_file, "w");
	if (out != NULL) {
		for (i = 0; i < nrows; i++) {
			for (j = 0; j < ncols; j++) fprintf(out, "%10.10f ", m[i][j]);
			fprintf(out, "\n");
		}
		fclose(out);
		jobDone = TRUE;
	}

	if (jobDone) return 1;
	else return 0;
}

int write_matrix_binary(char *id, char *dir, MATRIX_T m, int nrows, int ncols) {
	char output_file[FILE_PATH_LENGTH];
	BOOL jobDone = FALSE;
	FILE *out = NULL;
	int i, j;

	sprintf(output_file, "%s%s%s", dir, id, SUFFIX_MATRIX_BIN_FILE);
	out = fopen(output_file, "w");
	if (out != NULL) {
		for (i = 0; i < nrows; i++) {
			for (j = 0; j < ncols; j++) fwrite(&m[i][j], sizeof(double), 1,out);
			fprintf(out, "\n");
		}
		fclose(out);
		jobDone = TRUE;
	}

	if (jobDone) return 1;
	else return 0;
}

int main(int argc, char *argv[]) {
	BOOL jobDone = FALSE;
	char dir[FILE_PATH_LENGTH], id[TOKEN_LENGTH], type[TOKEN_LENGTH], ch;
	int nRequiredArgs = 3, nrows = DEFAULT_ROWS, ncols = DEFAULT_COLS, i, j;
	unsigned long seed = (unsigned long) time(NULL); 

	*dir = *id = *type = '\0';

	while ((ch = (char) getopt_long(argc, argv, "i:d:t", long_options, NULL)) != -1) {
		long value;
		switch (ch) {
			case 'i':
				strcpy(id, optarg);
				nRequiredArgs--;
				break;
			case 'd':
				strcpy(dir, optarg);
				nRequiredArgs--;
				break;
			case 't':
				strcpy(type, optarg);
				nRequiredArgs--;
				break;
			case 'r':
				nrows = atoi(optarg);
				if (nrows <= 0) nrows = DEFAULT_ROWS;
				break;
			case 'c':
				ncols = atoi(optarg);
				if (ncols <= 0) ncols = DEFAULT_COLS;
				break;
			case 's':
				value = atol(optarg);
				if (value != 0) seed = value;
				break;
			default:
				break;
		}
	}
	init_genrand(seed);
	
	if (nRequiredArgs != 0) {
		fprintf(stderr, "WARNING: Not all required arguments specified\n");
		return -1;
	}

	if (strcmp(type, TYPE_DOUBLE) == 0) {
		long int limit = ncols * nrows;
		MATRIX_T m = create_matrix(nrows, ncols, 0);
		if (m != NULL) {
			for (i = 0; i < nrows; i++) {
				for (j = 0; j < ncols; j++) m[i][j] = (double) get_rand(limit);
			}
			if (write_dims(id, nrows, ncols, type, dir)) {
				if (write_matrix_text(id, dir, m, nrows, ncols)) {
					if (write_matrix_binary(id, dir, m, nrows, ncols)) {
						jobDone = TRUE;
					}
				}
			}
			free_matrix(&m);
		}
	}

	if (jobDone) return 0;
	else return -1;
}